﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;

namespace SwParaPlatform2
{
    public static class XmlHandler
    {
        private const string ListSeparator = "|~|"; // 使用不常见的分隔符
        private const string ListTag = "IsList"; // 标记列表的属性名称
        private const string DictTag = "IsDict"; // 标记字典的属性名称
        private const string AtReplacement = "_rep_at_"; // 用于替换@符号
        private const string YiBReplacement = "_rep_100_"; // 用于替换%符号

        public static void WriteDictionaryToXml(string filePath, Dictionary<string, Dictionary<string, object>> dictionary, string rootElementName)
        {
            XElement root;

            if (File.Exists(filePath))
            {
                // 文件存在，加载现有的XML文档
                var document = XDocument.Load(filePath);
                root = document.Root ?? new XElement("Root");

                var existingRootElement = root.Element(ReplaceAtSymbol(rootElementName));
                if (existingRootElement != null)
                {
                    // 存在同名的根元素，清除其子元素
                    existingRootElement.RemoveAll();
                }
                else
                {
                    // 不存在同名的根元素，创建新的根元素并添加到文档
                    existingRootElement = new XElement(ReplaceAtSymbol(rootElementName));
                    root.Add(existingRootElement);
                }

                foreach (var outerKeyValuePair in dictionary)
                {
                    var outerElement = new XElement(ReplaceAtSymbol(outerKeyValuePair.Key));
                    AddDictionaryToElement(outerElement, outerKeyValuePair.Value);
                    existingRootElement.Add(outerElement);
                }

                // 将更新后的文档保存回文件
                document.Save(filePath);
            }
            else
            {
                // 文件不存在，创建新的文档
                root = new XElement("Root");
                var newRootElement = new XElement(ReplaceAtSymbol(rootElementName));
                root.Add(newRootElement);

                foreach (var outerKeyValuePair in dictionary)
                {
                    var outerElement = new XElement(ReplaceAtSymbol(outerKeyValuePair.Key));
                    AddDictionaryToElement(outerElement, outerKeyValuePair.Value);
                    newRootElement.Add(outerElement);
                }

                var document = new XDocument(root);
                document.Save(filePath);
            }
        }

        private static void AddDictionaryToElement(XElement element, IDictionary dictionary)
        {
            foreach (DictionaryEntry entry in dictionary)
            {
                var innerElement = new XElement(ReplaceAtSymbol(entry.Key.ToString()));

                if (entry.Value is IEnumerable enumerable && !(entry.Value is string))
                {
                    innerElement.SetAttributeValue(ListTag, true); // 标记为列表
                    AddEnumerableToElement(innerElement, enumerable); // 递归处理列表
                }
                else if (entry.Value is IDictionary innerDict)
                {
                    innerElement.SetAttributeValue(DictTag, true); // 标记为字典
                    AddDictionaryToElement(innerElement, innerDict); // 递归处理嵌套字典
                }
                else if (entry.Value is Dictionary<string, object> innerDict2)
                {
                    innerElement.SetAttributeValue(DictTag, true); // 标记为字典
                    AddDictionaryToElement(innerElement, (IDictionary)innerDict2); // 递归处理嵌套字典
                }
                else if (entry.Value is KeyValuePair<string, object> innerKvp2)
                {
                    var dictionary2 = DictionaryConverter.ConvertKeyValuePairToDictionary(innerKvp2);
                    innerElement.SetAttributeValue(DictTag, true); // 标记为字典
                    AddDictionaryToElement(innerElement, (IDictionary)dictionary2); // 递归处理嵌套字典
                }
                else if (entry.Value is Dictionary<string, Dictionary<string, object>> innerDict3)
                {
                    innerElement.SetAttributeValue(DictTag, true); // 标记为字典
                    AddDictionaryToElement(innerElement, (IDictionary)innerDict3); // 递归处理嵌套字典
                }
                else if (entry.Value is KeyValuePair<string, Dictionary<string, object>> innerKvp3)
                {
                    var dictionary3 = DictionaryConverter.ConvertKeyValuePairToDictionary(innerKvp3);
                    innerElement.SetAttributeValue(DictTag, true); // 标记为字典
                    AddDictionaryToElement(innerElement, (IDictionary)dictionary3); // 递归处理嵌套字典
                }
                else
                {
                    innerElement.Value = entry.Value?.ToString() ?? string.Empty;
                }

                element.Add(innerElement);
            }
        }

        private static void AddEnumerableToElement(XElement element, IEnumerable enumerable)
        {

            foreach (var item in enumerable)
            {

                if (item is IDictionary dict)
                {
                    var dictElement = new XElement("Item");
                    dictElement.SetAttributeValue(DictTag, true);
                    AddDictionaryToElement(dictElement, dict);
                    element.Add(dictElement);
                }
                else if (item is Dictionary<string, object> dict2)
                {
                    var dictElement = new XElement("Item");
                    dictElement.SetAttributeValue(DictTag, true);
                    AddDictionaryToElement(dictElement, (IDictionary)dict2);
                    element.Add(dictElement);
                }
                else if (item is KeyValuePair<string, object> kvp2)
                {
                    var dictionary2 = DictionaryConverter.ConvertKeyValuePairToDictionary(kvp2);
                    var dictElement = new XElement("Item");
                    dictElement.SetAttributeValue(DictTag, true);
                    AddDictionaryToElement(dictElement, (IDictionary)dictionary2);
                    element.Add(dictElement);
                }
                else if (item is Dictionary<string, Dictionary<string, object>> dict3)
                {
                    var dictElement = new XElement("Item");
                    dictElement.SetAttributeValue(DictTag, true);
                    AddDictionaryToElement(dictElement, (IDictionary)dict3);
                    element.Add(dictElement);
                }
                else if (item is KeyValuePair<string, Dictionary<string, object>> kvp3)
                {
                    var dictionary3 = DictionaryConverter.ConvertKeyValuePairToDictionary(kvp3);
                    var dictElement = new XElement("Item");
                    dictElement.SetAttributeValue(DictTag, true);
                    AddDictionaryToElement(dictElement, (IDictionary)dictionary3);
                    element.Add(dictElement);
                }
                else if (item is IEnumerable subEnumerable && !(item is string))
                {
                    var subListElement = new XElement("Item");
                    subListElement.SetAttributeValue(ListTag, true);
                    AddEnumerableToElement(subListElement, subEnumerable);
                    element.Add(subListElement);
                }
                else
                {
                    var itemElement = new XElement("Item", item?.ToString() ?? string.Empty);
                    element.Add(itemElement);
                }
            }
        }

        public static Dictionary<string, Dictionary<string, object>> ReadDictionaryFromXml(string rootElementName)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                openFileDialog.Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.*";
                openFileDialog.FilterIndex = 1;
                openFileDialog.RestoreDirectory = true;

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    string filePath = openFileDialog.FileName;

                    try
                    {
                        var document = XDocument.Load(filePath);
                        var root = document.Root;

                        if (root == null)
                        {
                            throw new InvalidOperationException($"Root element not found.");
                        }

                        var rootElement = root.Element(ReplaceAtSymbol(rootElementName));
                        if (rootElement == null)
                        {
                            throw new InvalidOperationException($"Element '{rootElementName}' not found.");
                        }

                        var dictionary = new Dictionary<string, Dictionary<string, object>>();

                        foreach (var outerElement in rootElement.Elements())
                        {
                            var innerDictionary = ReadDictionaryFromElement(outerElement);
                            dictionary[RestoreAtSymbol(outerElement.Name.LocalName)] = innerDictionary;
                        }

                        return dictionary;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"Error reading XML file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }

            return null;
        }

        private static Dictionary<string, object> ReadDictionaryFromElement(XElement element)
        {
            var dictionary = new Dictionary<string, object>();

            foreach (var innerElement in element.Elements())
            {
                if (innerElement.Attribute(ListTag) != null) // 判断是否是列表
                {
                    var list = ReadEnumerableFromElement(innerElement);
                    dictionary[RestoreAtSymbol(innerElement.Name.LocalName)] = list;
                }
                else if (innerElement.Attribute(DictTag) != null) // 判断是否是字典
                {
                    var subDict = ReadDictionaryFromElement(innerElement);
                    dictionary[RestoreAtSymbol(innerElement.Name.LocalName)] = subDict;
                }
                else
                {
                    dictionary[RestoreAtSymbol(innerElement.Name.LocalName)] = innerElement.Value;
                }
            }

            return dictionary;
        }

        private static List<object> ReadEnumerableFromElement(XElement element)
        {
            var list = new List<object>();

            foreach (var itemElement in element.Elements("Item"))
            {
                if (itemElement.Attribute(DictTag) != null)
                {
                    var dict = ReadDictionaryFromElement(itemElement);
                    list.Add(dict);
                }
                else if (itemElement.Attribute(ListTag) != null)
                {
                    var subList = ReadEnumerableFromElement(itemElement);
                    list.Add(subList);
                }
                else
                {
                    list.Add(itemElement.Value);
                }
            }

            return list;
        }

        private static string ReplaceAtSymbol(string name)
        {
            return name.Replace("@", AtReplacement).Replace("%", YiBReplacement);
        }

        // 恢复@符号
        private static string RestoreAtSymbol(string name)
        {
            return name.Replace(AtReplacement, "@").Replace(YiBReplacement, "%");
        }

        static Dictionary<K, V> ConvertKeyValuePairsToDictionary<K, V>(IEnumerable<KeyValuePair<K, V>> keyValuePairs)
        {
            // 创建一个新的 Dictionary 来存储转换后的数据
            var dictionary = new Dictionary<K, V>();

            // 遍历所有 KeyValuePair，将它们添加到字典中
            foreach (var kvp in keyValuePairs)
            {
                dictionary[kvp.Key] = kvp.Value; // 使用键和值填充字典
            }

            return dictionary; // 返回填充好的字典
        }
    }

    public static class DictionaryConverter
    {
        /// <summary>
        /// 通用方法：将 KeyValuePair 转换为 Dictionary。
        /// </summary>
        /// <typeparam name="K">字典的键类型。</typeparam>
        /// <typeparam name="V">字典的值类型。</typeparam>
        /// <param name="item">要转换的 KeyValuePair。</param>
        /// <returns>转换后的 Dictionary。</returns>
        public static Dictionary<K, object> ConvertKeyValuePairToDictionary<K, V>(KeyValuePair<K, V> item)
        {
            var result = new Dictionary<K, object>();

            // 获取 KeyValuePair 的值
            object value = item.Value;

            // 如果值是字典
            if (value is IDictionary dictionary)
            {
                // 将其转换为 Dictionary<K, object>
                result[item.Key] = ConvertToGenericDictionary(dictionary);
            }
            // 如果值是列表
            else if (value is IEnumerable enumerable && !(value is string))
            {
                // 转换为 List<object>
                var list = new List<object>();
                foreach (var element in enumerable)
                {
                    if (element is IDictionary elemDict)
                    {
                        // 如果元素是字典，则递归转换
                        list.Add(ConvertToGenericDictionary(elemDict));
                    }
                    else
                    {
                        // 否则直接添加
                        list.Add(element);
                    }
                }
                result[item.Key] = list;
            }
            else
            {
                // 如果是普通对象，直接添加
                result[item.Key] = value;
            }

            return result;
        }

        /// <summary>
        /// 将非泛型字典转换为 Dictionary<string, object>。
        /// </summary>
        /// <param name="dictionary">要转换的非泛型字典。</param>
        /// <returns>转换后的 Dictionary<string, object>。</returns>
        private static Dictionary<string, object> ConvertToGenericDictionary(IDictionary dictionary)
        {
            var genericDict = new Dictionary<string, object>();

            foreach (DictionaryEntry entry in dictionary)
            {
                if (entry.Value is IDictionary nestedDict)
                {
                    // 递归转换嵌套字典
                    genericDict[entry.Key.ToString()] = ConvertToGenericDictionary(nestedDict);
                }
                else if (entry.Value is IEnumerable enumerable && !(entry.Value is string))
                {
                    // 转换列表
                    var list = new List<object>();
                    foreach (var element in enumerable)
                    {
                        if (element is IDictionary elemDict)
                        {
                            list.Add(ConvertToGenericDictionary(elemDict));
                        }
                        else
                        {
                            list.Add(element);
                        }
                    }
                    genericDict[entry.Key.ToString()] = list;
                }
                else
                {
                    // 直接添加普通对象
                    genericDict[entry.Key.ToString()] = entry.Value;
                }
            }

            return genericDict;
        }
    }
}
